﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Windows.Shapes;
using System.Windows.Controls;
using System.Windows;

using TJDevHouse.Starcraft.Game;

using System.Windows.Media;

namespace TJDevHouse.Starcraft.MapAnalyser.MapDrawing
{
	/// <summary>
	/// A drawing of a map.
	/// </summary>
	public class MapDisplay
	{
		/// <summary>
		/// The map to draw
		/// </summary>
		public Map Map { get; private set; }

		/// <summary>
		/// The canvas to draw upon
		/// </summary>
		public Canvas MapCanvas { get; private set; }

		/// <summary>
		/// The size in pixels of each tile - calculated using map size & the size of canvas
		/// </summary>
		public double BuildTileSize { get; private set; }

		public double WalkTileSize { get; private set; } 

		//private Double UnitSize { get; private set; } //TODO use actual unit sizes instead of this

		/// <summary>
		/// The map layers to draw
		/// </summary>
		private List<MapLayer> MapLayers { get; set; }

		/// <summary>
		/// A read only collection of map layers.
		/// </summary>
		public ReadOnlyCollection<MapLayer> ReadOnlyMapLayers
		{
			get { return MapLayers.AsReadOnly(); }
		}


		public MapDisplay(Map map, Canvas canvas)
		{
			Map = map;
			MapCanvas = canvas;

			MapLayers = new List<MapLayer>();

			CalculateTileSize();
		}

		/// <summary>
		/// Add a layer to the map.
		/// 
		/// Layers will be rendered in the order they are passed to the
		/// drawing.
		/// 
		/// Will set the layer's Display property.
		/// </summary>
		/// <param name="layer"></param>
		public void AddMapLayer(MapLayer layer)
		{
			//layer.SetMapDisplay(this);
			MapLayers.Add(layer);
		}

		/// <summary>
		/// Calculate the size of each map tile (how to scale the map.)
		/// </summary>
		private void CalculateTileSize()
		{
			int mapWidth = Map.MapWalkableWidth;
			int mapHeight = Map.MapWalkableHeight;

			if (MapCanvas.ActualWidth / MapCanvas.ActualHeight <= (double)mapWidth / (double)mapHeight)
			{
				WalkTileSize = Math.Round(MapCanvas.ActualWidth / mapWidth, 2);
			}
			else
			{
				WalkTileSize = Math.Round(MapCanvas.ActualHeight / mapHeight, 2);
			}

			BuildTileSize = WalkTileSize * 4;
		}

		/// <summary>
		/// Positions the supplied element on the canvas.
		/// 
		/// Will convert the given coordinates into canvas specific coordinates (so just give the unit's
		/// map tile position)
		/// </summary>
		/// <param name="element"></param>
		/// <param name="tileX"></param>
		/// <param name="tileY"></param>
		public void PositionElementByBuildTile(UIElement element, int tileX, int tileY)
		{
			Canvas.SetLeft(element, tileX * BuildTileSize);
			Canvas.SetTop(element, tileY * BuildTileSize);
		}

		public void PositionElementByBuildTile(UIElement element, BuildTile tile)
		{
			PositionElementByBuildTile(element, tile.X, tile.Y);
		}

		public void PositionElementByWalkTile(UIElement element, int tileX, int tileY)
		{
			Canvas.SetLeft(element, tileX * WalkTileSize);
			Canvas.SetTop(element, tileY * WalkTileSize);
		}

		public void PositionElementByWalkTile(UIElement element, WalkTile tile)
		{
			PositionElementByBuildTile(element, tile.X, tile.Y);
		}
		

		/// <summary>
		/// Renders the map layers onto the canvas
		/// </summary>
		public void Render()
		{
			CalculateTileSize();
			MapCanvas.Children.Clear();
			foreach (MapLayer layer in MapLayers)
			{
				layer.Render(this);
			}
		}

		public Path CreateElipsePath(Brush fill, double tileWidth, double tileHeight)
		{
			Geometry unitPoint = new EllipseGeometry()
			{
				Center = new Point(
					tileWidth * BuildTileSize / 2, tileHeight * BuildTileSize / 2
				),
				RadiusX = tileWidth * BuildTileSize / 2,
				RadiusY = tileHeight * BuildTileSize / 2
			};
			Path path = new Path();
			path.Fill = fill;
			//path.Stroke = new SolidColorBrush(c);
			path.Data = unitPoint;

			return path;
		}

		public Path CreateRectanglePath(Brush fill, double tileWidth, double tileHeight)
		{
			Geometry unitPoint = new RectangleGeometry()
			{
				Rect = new Rect((tileWidth * BuildTileSize) / 2, (tileHeight * BuildTileSize) / 2, tileWidth * BuildTileSize, tileHeight * BuildTileSize)
			};

			Path path = new Path();
			path.Fill = fill;
			//path.Stroke = new SolidColorBrush(c);
			path.Data = unitPoint;

			return path;
		}

		/// <summary>
		/// Translate a point on a canvas to a walk tile coordinate
		/// </summary>
		/// <param name="point"></param>
		/// <returns></returns>
		public WalkTileMapCoordinate GetWalkTileCoordFromPoint(Point point)
		{
			WalkTileMapCoordinate wt;
			wt = new WalkTileMapCoordinate((int)(point.X / WalkTileSize), (int)(point.Y / WalkTileSize));

			return wt;
		}

		/// <summary>
		/// Get a specific map walk tile from the point coords
		/// </summary>
		/// <param name="point"></param>
		/// <returns></returns>
		public WalkTile GetWalkTileFromPoint(Point point)
		{
			return Map.GetWalkTile(GetWalkTileCoordFromPoint(point));
		}
	}
}
